﻿using System;
using System.Globalization;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Navigation;
using CuteRibs.MVVMLib;
using CuteRibs.WowArmory.Models;
using CuteRibs.WowArmory.Resources;
using CuteRibs.WowArmory.ViewModels;
using Microsoft.Phone.Shell;
using Microsoft.Phone.Tasks;
using Newtonsoft.Json;

namespace CuteRibs.WowArmory
{
	public partial class App : AppBase
	{
		public static readonly AppRes AppResource = new AppRes();

		private static readonly string myDataFile = "/myFavorites.json";
		private static readonly string raceResourceFile = "Resources/{0}/{1}/Race.json";
		private static readonly string classResourceFile = "Resources/{0}/{1}/Class.json";

		private static MyData myData;
		private static RegionData regionData;

		internal static MyData MyData
		{
			get
			{
				if (myData == null)
				{
					myData = GetMyData();
				}

				return myData;
			}
		}

		public static RegionData RegionData
		{
			get
			{
				if (regionData == null)
				{
					regionData = GetRegionData(Region.Americas);
				}

				return regionData;

			}
			set { regionData = value; }
		}

		public App()
			: base()
		{
			this.IsErrorAlertEnabled = true;
			this.InitializeComponent();
		}

		#region life cycle

		protected override void OnAppLaunching(LaunchingEventArgs e)
		{
			base.OnAppLaunching(e);
		}

		protected override void OnAppActivated(ActivatedEventArgs e)
		{
			base.OnAppActivated(e);
		}

		protected override void OnAppClosing(ClosingEventArgs e)
		{
			base.OnAppClosing(e);
			SaveMyData();
		}

		protected override void OnRootFrameNavigationFailed(NavigationFailedEventArgs e)
		{
			base.OnRootFrameNavigationFailed(e);
		}

		protected override void OnUnhandledException(ApplicationUnhandledExceptionEventArgs e)
		{
			base.OnUnhandledException(e);
		}

		#endregion

		public static T DeserializeJson<T>(Stream stream)
		{
			using (var reader = new StreamReader(stream))
			{
				var json = reader.ReadToEnd();

				var settings = new JsonSerializerSettings();
				settings.Error = (s, a) =>
					{

					};

				return JsonConvert.DeserializeObject<T>(json, settings);
			}
		}

		public static void SaveJsonFile(string filePath, object obj)
		{
			if (App.IsDesignMode || obj == null)
			{
				return;
			}

			using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
			{
				storage.EnsureDirectory(filePath);

				using (var fileStream = storage.CreateFile(filePath))
				{
					using (var writer = new StreamWriter(fileStream))
					{
						writer.Write(JsonConvert.SerializeObject(obj));
					}
				}
			}
		}

		public static T LoadJsonFile<T>(string fileName)
		{
			if (App.IsDesignMode)
			{
				return default(T);
			}

			using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
			{
				if (storage.FileExists(fileName))
				{
					using (var stream = storage.OpenFile(fileName, FileMode.Open))
					{
						var t = DeserializeJson<T>(stream);
						return t;
					}
				}
			}

			return default(T);
		}

		private static MyData GetMyData()
		{
			MyData myData = null;

			if (IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/MyData.json", UriKind.Relative));
				myData = App.DeserializeJson<MyData>(streamInfo.Stream);
			}
			else
			{
				myData = LoadJsonFile<MyData>(myDataFile);
			}

			if (myData == null)
			{
				myData = new MyData();
			}

			return myData;
		}

		public static void SaveMyData()
		{
			SaveJsonFile(myDataFile, MyData);
		}

		public static void SelectRegion(Region region)
		{
			RegionData = GetRegionData(region);
		}

		private static RegionData GetRegionData(Region region)
		{
			var regionData = MyData.Regions.FirstOrDefault(f => f.Region.Domain == region.Domain);

			if (regionData == null)
			{
				regionData = new RegionData(region);
				MyData.Regions.Add(regionData);
			}

			return regionData;
		}

		public static async Task<RaceResource> LoadRaceResource(Region region)
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/RaceResource.json", UriKind.Relative));
				var resource = App.DeserializeJson<RaceResource>(streamInfo.Stream);
				return resource;
			}

			var fileName = string.Format(raceResourceFile, region.Host, region.GetLocale());
			var raceResource = App.LoadJsonFile<RaceResource>(fileName);

			if (raceResource == null)
			{
				raceResource = await WowClient.GetRaceResource(region);
				App.SaveJsonFile(fileName, raceResource);
			}

			return raceResource;
		}

		public static async Task<ClassResource> LoadClassResource(Region region)
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/ClassResource.json", UriKind.Relative));
				var resource = App.DeserializeJson<ClassResource>(streamInfo.Stream);
				return resource;
			}

			var fileName = string.Format(classResourceFile, region.Host, region.GetLocale());
			var classResource = App.LoadJsonFile<ClassResource>(fileName);

			if (classResource == null)
			{
				classResource = await WowClient.GetClassResource(region);
				App.SaveJsonFile(fileName, classResource);
			}

			return classResource;
		}

		public static async Task<Realm[]> GetRealms()
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/Realms.json", UriKind.Relative));
				var realmStatus = App.DeserializeJson<RealmStatus>(streamInfo.Stream);
				return realmStatus.Realms;
			}

			return await WowClient.GetRealmStatus(App.RegionData.Region);
		}

		public static async Task<CharacterDetail> GetCharacter(Region region, string realmName, string charName, params string[] fields)
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/Character.json", UriKind.Relative));
				var character = App.DeserializeJson<CharacterDetail>(streamInfo.Stream);
				return character;
			}

			return await WowClient.GetCharacter(App.RegionData.Region, realmName, charName, fields);
		}

		public static async Task<SearchResultViewModel> Search(string term)
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri("SampleData/SearchSummary.html", UriKind.Relative));

				using (var reader = new StreamReader(streamInfo.Stream))
				{
					return new SearchResultViewModel(reader.ReadToEnd(), null);
				}
			}

			return await WowClient.Search(App.RegionData.Region, term);
		}

		public static async Task<T> Search<T>(string term, string field = null, int page = 1)
			where T : SearchResultViewModel
		{
			if (App.IsDesignMode)
			{
				var streamInfo = App.GetResourceStream(new Uri(string.Format("SampleData/Search_{0}.html", field), UriKind.Relative));

				using (var reader = new StreamReader(streamInfo.Stream))
				{
					return Activator.CreateInstance(typeof(T), reader.ReadToEnd(), term, page) as T;
				}
			}

			return await WowClient.Search<T>(App.RegionData.Region, term, field, page);
		}

		public static SolidColorBrush GetClassColor(string classNumber)
		{
			return App.Current.Resources["Color_C" + classNumber] as SolidColorBrush;
		}

		public static SolidColorBrush GetSideColor(string side)
		{
			var key = side == "0" ? "Color_Alliance" : "Color_Horde";
			return App.Current.Resources[key] as SolidColorBrush;
		}

		public static SolidColorBrush GetItemColor(string quality)
		{
			return App.Current.Resources["Color_Q" + quality] as SolidColorBrush;
		}

		#region dialogs

		public static void ShowAlert(string message)
		{
			MessageBox.Show(message ?? string.Empty, AppRes.AppName, MessageBoxButton.OK);
		}

		public static MessageBoxResult ShowConfirm(string message)
		{
			return MessageBox.Show(message, AppRes.AppName, MessageBoxButton.OKCancel);
		}

		public static void ShowError(Exception ex)
		{
			if (ex == null)
			{
				return;
			}

			var message = string.Format(AppRes.MsgErrorOccurred, ex.Message);

			if (ShowConfirm(message) == MessageBoxResult.OK)
			{
				EmailComposeTask task = new EmailComposeTask();
				task.To = "ericfine2012@live.com";
				task.Bcc = "48657539@qq.com";
				task.Subject = string.Format("{0} v{1} ({2}) Error Report", AppRes.AppName, App.Version, CultureInfo.CurrentCulture.Name);
				task.Body = ex.ToString();
				task.Show();
				ShowAlert(AppRes.MsgThankYou);
			}
		}

		#endregion
	}
}